#include "util/util.h"
using namespace util;
const int SCR_W = 640;
const int SCR_H = 480;
CGeometry obj;
float ang1 = 0, ang2 = 0, ang3 = 0;
float scale = 1.0f;
bool expand = false;
CTexture tex;
CCamera cam;

void init()
{
	glViewport(0, 0, SCR_W, SCR_H);
	glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
	glClearDepth(1.0);
	glEnable(GL_DEPTH_TEST);
	glShadeModel(GL_SMOOTH);
	glEnable(GL_NORMALIZE);
	glEnableClientState(GL_VERTEX_ARRAY);
	glEnableClientState(GL_NORMAL_ARRAY);
	glEnableClientState(GL_TEXTURE_COORD_ARRAY);
	
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	cam.perspective(45.0f, (float)SCR_W/SCR_H, 0.1f, 1000.f);
	
//	obj.create_sphere(128);
//	obj.create_torus(48);
	obj.create_cube();
	tex.set_filter_low();   // glGenerateMipmap doesn't work on ATI as of 2011
	tex.load_bmp("res/rock.bmp");
}
void frame()
{

}
void render()
{
	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
	
	// setup material
	static const float MAT_COLOR[] = { 0.2f, 0.2f, 0.2f, 1.0f };
	static const float MAT_SPECULAR[] = { 0.3f, 0.3f, 0.3f, 1.0f };
	glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, MAT_COLOR);
	glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, MAT_SPECULAR);
	glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 128.0f);
	
	// setup lights
	static const float WHITE[] = { 1.0f, 1.0f, 1.0f, 1.0f };
	static const float RED[] = { 1.0f, 0.0f, 0.0f, 1.0f };
	static const float GREEN[] = { 0.0f, 1.0f, 0.0f, 1.0f };
	static const float BLUE[] = { 0.0f, 0.0f, 1.0f, 1.0f };
	static const float YELLOW[] = { 1.0f, 1.0f, 0.0f, 1.0f };
	static const float GREY[] = { 0.1f, 0.1f, 0.1f, 1.0f };
	
	glEnable(GL_LIGHTING);
	
	glLightModelfv(GL_LIGHT_MODEL_AMBIENT, GREY);
	
	glEnable(GL_LIGHT0);
	glLightfv(GL_LIGHT0, GL_AMBIENT, WHITE);
	
	glEnable(GL_LIGHT1);
//	glLightfv(GL_LIGHT1, GL_AMBIENT, YELLOW);
	glLightfv(GL_LIGHT1, GL_DIFFUSE, YELLOW);
	glLightfv(GL_LIGHT1, GL_SPECULAR, YELLOW);
	
	glEnable(GL_LIGHT2);
//	glLightfv(GL_LIGHT2, GL_AMBIENT, BLUE);
	glLightfv(GL_LIGHT2, GL_DIFFUSE, BLUE);
	glLightfv(GL_LIGHT2, GL_SPECULAR, BLUE);
	
	glEnable(GL_LIGHT3);
//	glLightfv(GL_LIGHT3, GL_AMBIENT, GREEN);
	glLightfv(GL_LIGHT3, GL_DIFFUSE, GREEN);
	glLightfv(GL_LIGHT3, GL_SPECULAR, GREEN);
	
	glEnable(GL_LIGHT4);
//	glLightfv(GL_LIGHT4, GL_AMBIENT, RED);
	glLightfv(GL_LIGHT4, GL_DIFFUSE, RED);
	glLightfv(GL_LIGHT4, GL_SPECULAR, RED);
	
	// rotate these 4 spot lights
	static const float SCENE_DEPTH = -20.0f;
	glPushMatrix();
		glRotatef(ang1, 1, 0, 0);
		ang1 += 1.5f;
		
		static float l1pos[] = { 0, 5, SCENE_DEPTH + 3, 1};
		static float l1dir[] = { 0, -1, 0 };
		glLightfv(GL_LIGHT1, GL_POSITION, l1pos);
		glLightfv(GL_LIGHT1, GL_SPOT_DIRECTION, l1dir);
		glLightf(GL_LIGHT1, GL_SPOT_CUTOFF, 70.0f);
		glLightf(GL_LIGHT1, GL_SPOT_EXPONENT, 10.0f);
		
		static float l2pos[] = { 0, -5, SCENE_DEPTH + 3, 1 };
		static float l2dir[] = { 0, 1, 0 };
		glLightfv(GL_LIGHT2, GL_POSITION, l2pos);
		glLightfv(GL_LIGHT2, GL_SPOT_DIRECTION, l2dir);
		glLightf(GL_LIGHT2, GL_SPOT_CUTOFF, 70.0f);
		glLightf(GL_LIGHT2, GL_SPOT_EXPONENT, 10.0f);
	glPopMatrix();
	
	glPushMatrix();
		glRotatef(ang2, 0, 1, 0);
		ang2 += 1.5f;
		
		static float l3pos[] = { 5, 0, SCENE_DEPTH + 3, 1 };
		static float l3dir[] = { -1, 0, 0 };
		glLightfv(GL_LIGHT3, GL_POSITION, l3pos);
		glLightfv(GL_LIGHT3, GL_SPOT_DIRECTION, l3dir);
		glLightf(GL_LIGHT3, GL_SPOT_CUTOFF, 70.0f);
		glLightf(GL_LIGHT3, GL_SPOT_EXPONENT, 10.0f);
		
		static float l4pos[] = { -5, 0, SCENE_DEPTH + 3, 1 };
		static float l4dir[] = { 1, 0, 0 };
		glLightfv(GL_LIGHT4, GL_POSITION, l4pos);
		glLightfv(GL_LIGHT4, GL_SPOT_DIRECTION, l4dir);
		glLightf(GL_LIGHT4, GL_SPOT_CUTOFF, 70.0f);
		glLightf(GL_LIGHT4, GL_SPOT_EXPONENT, 10.0f);
	glPopMatrix();
	
	// bind texture
	glEnable(GL_TEXTURE_2D);
	glBindTexture(GL_TEXTURE_2D, tex.get_id());
	
	glVertexPointer(3, GL_FLOAT, 0, obj.get_vertex());
	glNormalPointer(GL_FLOAT, 0, obj.get_normal());
	glTexCoordPointer(2, GL_FLOAT, 0, obj.get_texcoord());
	
	// transform sphere
	glTranslatef(0.0f, 0.0f, SCENE_DEPTH);
	glRotatef(ang3, 1, 1, 1);
	glScalef(4, 4, 4);
	if (expand)   scale += 0.005f;
	else          scale -= 0.005f;
	if (scale < 0.5f)   expand = true;
	if (scale > 1.0f)   expand = false;
	ang3 += 1.5f;
	
//	glColor3f(0,1,0);
	glDrawElements(GL_TRIANGLES, obj.get_index_num(), GL_UNSIGNED_SHORT, obj.get_index_data());
}

int main()
{
	g_p_system = new CSystem(SCR_W, SCR_H, "Basic Light and Texture by qq.d.y");
	g_p_system->set_callback(CSystem::INIT, init);
	g_p_system->set_callback(CSystem::RENDER, render);
	g_p_system->set_callback(CSystem::FRAME, frame);
	g_p_system->run();
	return 0;
}